﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Net;
using System.Net.Sockets;



public class UDPClientsManager : ClientsManagerBase, IGameLifeCycle,ISocketServer
{
    //UDP所有Client共用一个Socket
    UDPSocketServer m_UDPSocketServer;
    public UDPSocketServer udpSocketServer => m_UDPSocketServer;

    protected override ServerSocket socketServer
    {
        get
        {
            if(m_UDPSocketServer == null)
            {
                m_UDPSocketServer = new UDPSocketServer(this);
            }
            return m_UDPSocketServer;
        }
    }

    /// <summary>
    /// 通讯失败判断为断线的判定次数
    /// </summary>
    //const int DisconnectJudgeCount = 8;

    //监听端口15001-16000
    const int portBegin = 15001;

    Queue<int> canUsePortQueue = new Queue<int>();
    int m_AddPortIndex;

    /// <summary>
    /// 获取可用端口
    /// </summary>
    /// <returns></returns>
    int GetCanUsePort()
    {
        int curPort = 0;

        lock (canUsePortQueue)
        {
            if (canUsePortQueue.Count <= 0)
            {
                //每次进10个端口待用
                int addCount = 10;
                int addPortBegin = portBegin + m_AddPortIndex * addCount;

                for (int i = addPortBegin; i < addPortBegin + addCount; i++)
                {
                    canUsePortQueue.Enqueue(i);
                }
                m_AddPortIndex++;
            }

            curPort = canUsePortQueue.Dequeue();
        }
        GameDebug.Log($"获取当前可用端口：{curPort}");

        return curPort;
    }
    /// <summary>
    /// 回收端口
    /// </summary>
    /// <param name="port"></param>
    void RecyclePort(int port)
    {
        lock (canUsePortQueue)
        {
            canUsePortQueue.Enqueue(port);
        }
    }
    

    public UDPClientsManager()
    {

    }
    
    public override void Start(int port, int maxConnectCount)
    {
        socketServer.Start(port, maxConnectCount);

        socketServer.BeginReceive();
    }

    #region ISocketServer

    public void OnReceiveData(EndPoint endPoint, byte[] data)
    {
        this.CheckNewConnect(endPoint, data);
    }

    public void OnRecOrSendFailed(EndPoint endPoint)
    {
        this.RemoveClient((IPEndPoint)endPoint);
        return;
    }

    #endregion

    void CheckNewConnect(EndPoint remoteEndPoint, byte[] data)
    {
        IPEndPointKey key = IPEndPointKey.GetIPEndPointKey((IPEndPoint)remoteEndPoint);

        Remote remote;
        bool exist = m_ClientList.TryGetValue(key, out remote);

        GameDebug.Log($"CheckNewConnect  m_UDPSocketServer:{m_UDPSocketServer.GetHashCode()}");

        if (!exist)
        {
            //新用户
            remote = OnNewClientConnected(remoteEndPoint);
        }

        UDPClient client = remote as UDPClient;

        if (client != null)
        {
            client.onDisconnect = RemoveClient;

            client.OnReceiveData(data);
        }
        else
        {
            GameDebug.LogError($"client == null:{remote == null}  {remote?.GetType().Name}");
        }
    }

    
    public UDPClient OnNewClientConnected(EndPoint endPoint)
    {
        IPEndPoint ip = (IPEndPoint)endPoint;

        UDPSocketServer connectScoketServer = new UDPSocketServer();

        UDPClient newClient = NewUDPClient(GetCurClientId(), ip, connectScoketServer);

        newClient.BeginReceive(GetCanUsePort());
        
        this.AddClient(ip, newClient);

        GameDebug.Log($"新用户上线:{newClient.ipEndPoint} connect socket:{connectScoketServer.socket?.GetHashCode()}  clientId:{newClient.clientId} \n dict:{m_ClientList.dictionary.GetDictStr()}");

        this.listener.OnNewClient(newClient);

        return newClient;

        //udpSocketServer.SendTo(endPoint, new byte[] { 8 });
    }
    
    protected virtual UDPClient NewUDPClient(long clientId,EndPoint endPoint, UDPSocketServer uDPSocketServer)
    {
        return new UDPClient(clientId, (IPEndPoint)endPoint, uDPSocketServer);
    }

    /// <summary>
    /// 添加登录用户
    /// </summary>
    /// <param name="userId"></param>
    /// <param name="_client"></param>
    public override void OnAddLoginedUser(long userId, Remote _client)
    {
        base.OnAddLoginedUser(userId,_client);

        IPEndPointKey key = IPEndPointKey.GetIPEndPointKey(_client.ipEndPoint);

        Remote remote;

        bool exist = m_ClientList.TryGetValue(key, out remote);

        if (exist)
        {
            UDPClient client = remote as UDPClient;

            if (client != null)
            {
                client.userID = userId;

                GameDebug.Log($"用户登入  userId:{client.userID}  clientId:{client.clientId}  ipEndPoint {client.ipEndPoint}");
            }
            else
            {
                GameDebug.LogError($"client == null  clientId:{remote?.clientId}");
            }
        }
        else
        {
#if DEBUG
            GameDebug.LogError($"did not exist _client.clientId:{_client.clientId} clientList:{m_ClientList.dictionary.GetDictStr()}");
#endif
        }
    }
    
    public override void RemoveClient(IPEndPoint endPoint)
    {
        Remote remote;
        this.m_ClientList.TryGetValue(IPEndPointKey.GetIPEndPointKey(endPoint), out remote);

        if(remote != null)
        {
            UDPClient udpClient = remote as UDPClient;

            GameDebug.LogShowy($"移除客户端连接：{remote.ipEndPoint}");

            if (udpClient != null)
            {
                //int toRecyclePort = udpClient.listenPort;

                udpClient.Disconnect();

                this.RecyclePort(udpClient.listenPort);
            }
            else
            {
#if DEBUG
                GameDebug.LogError($"remote == null:{remote == null}   {remote?.GetType().Name}");
#endif
            }

            base.RemoveClient(endPoint);
        }
        else
        {
#if DEBUG
            GameDebug.LogError($"cannot find client:{endPoint}  clientList:{this.m_ClientList.dictionary.GetDictStr()}");
#endif
        }
    }

    /// <summary>
    /// 有客户端断开连接
    /// </summary>
    /// <param name="rc"></param>
    protected virtual void OnRemoveDisconnet(UDPRemote rc)
    {
        UDPClient client = rc as UDPClient;

        this.RemoveClient(client.ipEndPoint);

        this.listener?.OnDisConnect(client);
    }

    public override void Update(int frameCount)
    {
       
    }


}

